from typing import Optional, List, Dict, Any
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, and_, or_, func
from sqlalchemy.orm import selectinload

from app.models.user import Permission, Role, role_permission_association
from app.services.base import BaseService


class PermissionService(BaseService[Permission]):
    """权限服务"""

    def __init__(self):
        super().__init__(Permission)

    async def get_permission_tree(
        self, db: AsyncSession, *, tenant_id: str
    ) -> List[Dict[str, Any]]:
        """获取权限树形结构"""
        # 查询所有权限
        query = select(Permission).where(
            and_(
                Permission.tenant_id == tenant_id,
                Permission.is_deleted == False,
                Permission.status == True
            )
        ).order_by(Permission.sort.asc())

        result = await db.execute(query)
        permissions = result.scalars().all()

        # 构建权限树
        return self._build_permission_tree(permissions)

    async def get_menu_tree(
        self, db: AsyncSession, *, tenant_id: str, visible_only: bool = True
    ) -> List[Dict[str, Any]]:
        """获取菜单树形结构"""
        query = select(Permission).where(
            and_(
                Permission.tenant_id == tenant_id,
                Permission.is_deleted == False,
                Permission.status == True,
                Permission.type.in_(['M', 'C'])  # M-目录, C-菜单
            )
        )

        if visible_only:
            query = query.where(Permission.visible == True)

        query = query.order_by(Permission.sort.asc())

        result = await db.execute(query)
        permissions = result.scalars().all()

        return self._build_permission_tree(permissions)

    def _build_permission_tree(
        self, permissions: List[Permission], parent_id: int = 0
    ) -> List[Dict[str, Any]]:
        """构建权限树形结构"""
        tree = []

        for permission in permissions:
            if permission.parent_id == parent_id:
                # 构建当前节点
                node = {
                    "id": permission.id,
                    "name": permission.name,
                    "code": permission.code,
                    "type": permission.type,
                    "parent_id": permission.parent_id,
                    "path": permission.path,
                    "component": permission.component,
                    "perms": permission.perms,
                    "icon": permission.icon,
                    "sort": permission.sort,
                    "is_frame": permission.is_frame,
                    "is_cache": permission.is_cache,
                    "visible": permission.visible,
                    "status": permission.status,
                    "remark": permission.remark,
                    "children": []
                }

                # 递归获取子节点
                children = self._build_permission_tree(permissions, permission.id)
                if children:
                    node["children"] = children

                tree.append(node)

        return tree

    async def get_role_permissions(
        self, db: AsyncSession, *, role_id: int, tenant_id: str
    ) -> List[Permission]:
        """获取角色的权限列表"""
        query = (
            select(Permission)
            .join(
                role_permission_association,
                Permission.id == role_permission_association.c.permission_id
            )
            .where(
                and_(
                    role_permission_association.c.role_id == role_id,
                    role_permission_association.c.tenant_id == tenant_id,
                    Permission.tenant_id == tenant_id,
                    Permission.is_deleted == False,
                    Permission.status == True
                )
            )
            .order_by(Permission.sort.asc())
        )

        result = await db.execute(query)
        return result.scalars().all()

    async def assign_permissions_to_role(
        self, db: AsyncSession, *, role_id: int, permission_ids: List[int], tenant_id: str
    ):
        """分配权限给角色"""
        # 删除现有权限关联
        await db.execute(
            role_permission_association.delete().where(
                and_(
                    role_permission_association.c.role_id == role_id,
                    role_permission_association.c.tenant_id == tenant_id
                )
            )
        )

        # 添加新权限关联
        if permission_ids:
            values = [
                {"role_id": role_id, "permission_id": permission_id, "tenant_id": tenant_id}
                for permission_id in permission_ids
            ]
            await db.execute(role_permission_association.insert().values(values))

        await db.commit()

    async def create_permission(
        self, db: AsyncSession, *, obj_in: Dict[str, Any], tenant_id: str
    ) -> Permission:
        """创建权限"""
        obj_in["tenant_id"] = tenant_id
        return await self.create(db, obj_in=obj_in)

    async def update_permission(
        self, db: AsyncSession, *, db_obj: Permission, obj_in: Dict[str, Any]
    ) -> Permission:
        """更新权限"""
        return await self.update(db, db_obj=db_obj, obj_in=obj_in)

    async def delete_permission(
        self, db: AsyncSession, *, id: int, tenant_id: str
    ) -> bool:
        """删除权限（软删除）"""
        permission = await self.get_by_id(db, id=id)
        if not permission or permission.tenant_id != tenant_id:
            return False

        # 检查是否有子权限
        children_query = select(Permission.id).where(
            and_(
                Permission.parent_id == id,
                Permission.tenant_id == tenant_id,
                Permission.is_deleted == False
            )
        )
        result = await db.execute(children_query)
        if result.scalar():
            raise ValueError("存在子权限，无法删除")

        # 软删除
        permission.is_deleted = True
        await db.commit()
        return True

    async def get_permissions_by_codes(
        self, db: AsyncSession, *, codes: List[str], tenant_id: str
    ) -> List[Permission]:
        """根据权限编码列表获取权限"""
        query = select(Permission).where(
            and_(
                Permission.code.in_(codes),
                Permission.tenant_id == tenant_id,
                Permission.is_deleted == False,
                Permission.status == True
            )
        )
        result = await db.execute(query)
        return result.scalars().all()

    async def get_by_code(
        self, db: AsyncSession, *, code: str, tenant_id: str
    ) -> Optional[Permission]:
        """根据权限编码获取权限"""
        query = select(Permission).where(
            and_(
                Permission.code == code,
                Permission.tenant_id == tenant_id,
                Permission.is_deleted == False
            )
        )
        result = await db.execute(query)
        return result.scalar_one_or_none()

    async def get_list(
        self,
        db: AsyncSession,
        *,
        tenant_id: str,
        skip: int = 0,
        limit: int = 20,
        keyword: Optional[str] = None
    ) -> tuple[List[Permission], int]:
        """获取权限列表（分页）"""
        query = select(Permission).where(
            and_(
                Permission.tenant_id == tenant_id,
                Permission.is_deleted == False
            )
        )

        # 添加搜索条件
        if keyword:
            search_filter = or_(
                Permission.name.like(f"%{keyword}%"),
                Permission.code.like(f"%{keyword}%"),
                Permission.remark.like(f"%{keyword}%")
            )
            query = query.where(search_filter)

        # 获取总数
        count_query = query.with_only_columns(func.count(Permission.id))
        count_result = await db.execute(count_query)
        total = count_result.scalar() or 0

        # 分页查询
        query = query.order_by(Permission.sort.asc()).offset(skip).limit(limit)
        result = await db.execute(query)
        permissions = result.scalars().all()

        return permissions, total


# 创建权限服务实例
permission_service = PermissionService()